package com.rs.mapper;

import com.jfinal.aop.Aop;
import com.rs.mapper.annotation.Dao;
import com.rs.mapper.annotation.Mapper;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Mappers
 * 1、生成dao代理对象
 * 2、扫描所有映射mapper
 * 3、注入dao
 */
public class Mappers {

    //mapper 路径
    private static Map<Class<?>,String> paths =new HashMap<>();

    //mapper代理对象
    private static Map<Class<?>,Object> os =new HashMap<>();

    private static Map<Class<?>,Object> entity =new HashMap<>();

    //用于使用多数据库
    private static Map<Class<?>,String> dbs =new HashMap<>();

    //mapper路径
    private String daoPath;

    //引用mapper的路径
    private String autowirePath;

    private Mappers(){}

    public Mappers(String daoPath,String autowirePath){
        this.daoPath =daoPath;
        this.autowirePath=autowirePath;
        this.scan();
        this.addOs();
        this.scanDaoAnnotationClass();
    }

    private void scan(){
        Reflections reflections = new Reflections(daoPath);
        Set<Class<?>> classes = reflections.getTypesAnnotatedWith(Mapper.class);
        for(Class<?> val: classes){
            Mapper val1 = val.getAnnotation(Mapper.class);
            String path = val1.path();
            String db = val1.db();
            if("".equals(path.trim())){
                path = val.getSimpleName();
            }
            paths.put(val,path);
            dbs.put(val,db);
        }
    }

    private void scanDaoAnnotationClass(){
        Reflections reflections = new Reflections(autowirePath,new FieldAnnotationsScanner());
        Set<Field> fields = reflections.getFieldsAnnotatedWith(Dao.class);
        for(Field val: fields){
            try {
                val.setAccessible(true);
                Type type =val.getGenericType();
                Class<?> t =Class.forName(type.getTypeName());
                val.set(Aop.get(val.getDeclaringClass()),Mappers.get(t));
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private void addOs(){
        for (Map.Entry<Class<?>,String> entry : paths.entrySet()) {
            Object val = this.generate(entry.getKey());
            os.put(entry.getKey(),val);
        }
    }




    private Object generate(Class<?> t){
        return  MapperProxyFactory.newInstance(t);
    }

    public static <T> T get(Class<?> t){
        return (T)os.get(t);
    }

    public static String interfaceName(Class<?> t,String methodName){
        String val = paths.get(t);
        return val.concat(".").concat(methodName);
    }

    public static String dbPath(Class<?> t){
        String val = dbs.get(t);
        val =val.trim();
        return val;
    }


    public static <T> T getEntity(Class<?> t){
        if(entity.get(t)!=null){
            return (T)entity.get(t);
        }else{
            try{
                Object o = t.newInstance();
                Class<?> val1 =  t.getSuperclass().getSuperclass();
                Method val =val1.getDeclaredMethod("dao");
                o =val.invoke(o);
                entity.put(t,o);
                return (T)o;
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return null;
    }

}
